package rollercoaster.train.tests;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JFrame;

import rollercoaster.commons.Vertex3D;
import rollercoaster.commons.interfaces.ICurve3D;
import rollercoaster.commons.interfaces.Surface3D;
import rollercoaster.railway.Trajectory;
import rollercoaster.railway.Tube;
import rollercoaster.railway.UniformSecondOrderClosedBSpline;
import rollercoaster.railway.tests.Curve3DTest.GraphicListener;
import rollercoaster.railway.utils.OBJFileVertexReader;
import rollercoaster.train.UniformClosedSecondOrderPatch;
import rollercoaster.train.UniformOpenSecondOrderPatch;
import rollercoaster.train.utils.OBJControlPointsMultipleSurfacesReader;
import rollercoaster.train.utils.OBJControlPointsSingleSurfaceReader;

import com.jogamp.opengl.util.FPSAnimator;

public class MultipleSurface3DTest extends JFrame{

	private static final long serialVersionUID = 1L;


	public static void main(String[] args) {
		MultipleSurface3DTest frame=new MultipleSurface3DTest();
		frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
	
	public MultipleSurface3DTest() {
		setSize(1200,1200);
		setTitle("Surface Test");
		GraphicListener listener=new GraphicListener();
		GLCanvas canvas=new GLCanvas();
		canvas.addGLEventListener(listener);
		getContentPane().add(canvas);
		canvas.addKeyListener(listener);
		addKeyListener(listener);
		FPSAnimator animator=new FPSAnimator(canvas,60);
		animator.start();
	}
	
	
	public static class GraphicListener implements GLEventListener,KeyListener{

		private static final int DIVISIONS_U=100;
		private static final int DIVISIONS_V=100;
		
		private int view_angle=-30;
		private int t=0;
		private float wx=1,hx=1;
		
		//private Surface3D surf;
		private List<Surface3D> surfaces=new ArrayList<Surface3D>();
		
		public void display(GLAutoDrawable arg0) {
			GL2 gl=(GL2) arg0.getGL();
			gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
			
			
			gl.glEnable(GL.GL_DEPTH_TEST);
			//gl.glCullFace(gl.GL_FRONT);
			//gl.glEnable(gl.GL_CULL_FACE);
			//gl.glFrontFace(gl.GL_CCW);
			gl.glDisable(gl.GL_CULL_FACE);
			
			gl.glMatrixMode(GL2.GL_PROJECTION);
			gl.glLoadIdentity();
			gl.glRotatef(view_angle, 1, 1, 0);
			gl.glScalef(1200/wx, 1200/hx, 1);

			
			gl.glMatrixMode(GL2.GL_MODELVIEW);
			gl.glLoadIdentity();
			gl.glScalef(0.02f, 0.02f, 0.02f);
			
			//drawSurfTerronamente(gl);
			drawSurf(gl);
			t++;
		}
		
		public void drawSurfTerronamente(GL2 gl){
			Surface3D surf;
			for (int k = 0; k < surfaces.size(); k++) {
				surf=surfaces.get(k);
				
				float stepu=surf.getEndUPoint()/DIVISIONS_U;
				float stepv=surf.getEndVPoint()/DIVISIONS_V;
				gl.glColor3f(1, 0, 0);
				gl.glShadeModel(GL2.GL_FLAT);
				for (int i = 0; i <= DIVISIONS_U; i++) {
					float u=stepu*i;
					gl.glBegin(GL.GL_LINE_STRIP);
					for (int j = 0; j <= DIVISIONS_V; j++) {
						float v=stepv*j;
						Vertex3D vv=surf.sigma(u,v);
						gl.glVertex3f(vv.getX(), vv.getY(), vv.getZ());
						if(t==0){
							//System.out.println(u+" "+v+": "+vv);
						}
					}
					gl.glEnd();
				}
				gl.glColor3f(1, 1, 0);
				for (int i = 0; i <= DIVISIONS_V; i++) {
					float v=stepv*i;
					gl.glBegin(GL.GL_LINE_STRIP);
					for (int j = 0; j <= DIVISIONS_U; j++) {
						float u=stepu*j;
						Vertex3D vv=surf.sigma(u,v);
						gl.glVertex3f(vv.getX(), vv.getY(), vv.getZ());
						if(t==0){
							//System.out.println(u+" "+v+": "+vv);
						}
					}
					gl.glEnd();
				}
				
				
			}
			
			
			
		}

		public void drawSurf(GL2 gl){
			Surface3D surf;
			for (int k = 0; k < surfaces.size(); k++) {
				surf=surfaces.get(k);
				
				float stepu=surf.getEndUPoint()/DIVISIONS_U;
				float stepv=surf.getEndVPoint()/DIVISIONS_V;
				
				//float stepu=1;
				//float stepv=1;
				
				for(int i=0;i<=DIVISIONS_V;i++){
					float v=stepv*i;
					float v1=v+stepv;
					gl.glBegin(GL.GL_TRIANGLE_STRIP);
						for(int j=0;j<=DIVISIONS_U;j++){
							float u=stepu*j;
							
							Vertex3D xyz=surf.sigma(u,v);
							float x=xyz.getX();
							float y=xyz.getY();
							float z=xyz.getZ();
							
							if(t==0){
								//System.out.println("v: "+xyz);
							}
							
							Vertex3D n=surf.getNormal(u, v);
							float nx=n.getX();
							float ny=n.getY();
							float nz=n.getZ();
							
							//Normale e vertice (u,v)
							gl.glNormal3f(nx, ny, nz);
							gl.glVertex3f(x,y,z);
							
							xyz=surf.sigma(u,v1);
							x=xyz.getX();
							y=xyz.getY();
							z=xyz.getZ();
							
							if(t==0){
								//System.out.println("v1: "+xyz);
							}
							
							n=surf.getNormal(u, v1);
							nx=n.getX();
							ny=n.getY();
							nz=n.getZ();
				
							//Normale e vertice (u,v)
							gl.glNormal3f(nx, ny, nz);
							gl.glVertex3f(x,y,z);
						}
					gl.glEnd();
				}
			}
			
			
		}
		

		public void dispose(GLAutoDrawable arg0) {
			// TODO Auto-generated method stub
			
		}

	
		public void init(GLAutoDrawable arg0) {
			GL2 gl=(GL2) arg0.getGL();
			gl.glEnable(GL2.GL_LIGHTING);
			float ambient[]={0.5f,0.5f,0.5f,1};
			gl.glLightModelfv(GL2.GL_LIGHT_MODEL_AMBIENT, ambient, 0);
			
			gl.glEnable(GL2.GL_LIGHT4);
			float position4[]={1,0,1,1};
			gl.glLightfv(GL2.GL_LIGHT4, gl.GL_POSITION, position4,0);
			float intensity4[]={1,1,1,1};
			gl.glLightfv(GL2.GL_LIGHT4, gl.GL_DIFFUSE, intensity4,0);
			gl.glLightf(GL2.GL_LIGHT4,GL2.GL_LINEAR_ATTENUATION,0.5f);
			
			
			gl.glEnable(GL2.GL_COLOR_MATERIAL);
			gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL2.GL_AMBIENT_AND_DIFFUSE);
			float specColor[]={1,1,1,1};
			gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL2.GL_SPECULAR, specColor, 0);
			gl.glMaterialf(GL.GL_FRONT_AND_BACK, GL2.GL_SHININESS, 80);
			
			//Instance of the surf
			OBJControlPointsMultipleSurfacesReader reader=new OBJControlPointsMultipleSurfacesReader("trainModels/vagone/vagoneQuadratoTuttoG2.obj");
			
			Vertex3D[][] controlPoints;
			Surface3D surf;
			List<Vertex3D[][]> controlPointsList=reader.getControlPointsList();
			int numSurfaces=controlPointsList.size();
			
			for (int i = 0; i < numSurfaces; i++) {
				controlPoints=controlPointsList.get(i);
				surf=new UniformOpenSecondOrderPatch(controlPoints);
				//System.out.println(i);
				surfaces.add(surf);
			}
			
		}

		public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3,
				int arg4) {
			GL gl=arg0.getGL();
			
			wx=arg3;
			hx=arg4;
			
		}

		public void keyTyped(KeyEvent e) {
			// TODO Auto-generated method stub
			
		}


		public void keyPressed(KeyEvent e) {
			if(e.getKeyCode()==KeyEvent.VK_UP){
				view_angle+=5;
			}
			if(e.getKeyCode()==KeyEvent.VK_DOWN){
				view_angle-=5;
			}
			
		}

		
		public void keyReleased(KeyEvent e) {
			// TODO Auto-generated method stub
			
		}
		
	}
}
